﻿namespace System;

public struct Date
{
    private readonly DateTime _date;
    public int Year => _date.Year;
    public int Month => _date.Month;
    public int Day => _date.Day;
    public static readonly Date MinValue = new(DateTime.MinValue.Date);
    public static readonly Date MaxValue = new(DateTime.MaxValue.Date);
    public Date()
        : this(DateTime.MinValue)
    {
    }
    public Date(int year, int month, int day)
        : this(new DateTime(year, month, day))
    {
    }
    public Date(DateTime dateTime)
    {
        _date = dateTime;
    }
    public Date AddYears(int year)
    {
        return new Date(Year + year, Month, Day);
    }
    public Date AddMonths(int month)
    {
        return new Date(Year, Month + month, Day);
    }
    public Date AddDays(int day)
    {
        return new Date(Year, Month, Day + day);
    }
    public override string ToString()
    {
        return _date.ToString();
    }
    public string ToString(string format)
    {
        return _date.ToString(format);
    }
    public DateTime ToDateTime()
    {
        return _date;
    }
    public bool IsBetween(Date a, Date b)
    {
        return a._date <= _date && _date <= b._date;
    }
    public override bool Equals(object obj)
    {
        if (obj is Date date)
        {
            return date._date == _date;
        }
        return false;
    }
    public override int GetHashCode()
    {
        return _date.GetHashCode();
    }

    public static Date Today
    {
        get
        {
            return new Date(DateTime.Today);
        }
    }

    public static Date Yesterday
    {
        get
        {
            return new Date(DateTime.Today.AddDays(-1));
        }
    }

    public static Date Tomorrow
    {
        get
        {
            return new Date(DateTime.Today.AddDays(1));
        }
    }

    public static Date Parse(string value)
    {
        var date = DateTime.Parse(value);
        if(date.Ticks != date.Date.Ticks)
        {
            throw new FormatException();
        }
        return new Date(date);
    }
    public static bool TryParse(string value, out Date dateValue)
    {
        if (DateTime.TryParse(value, out var _dateTime))
        {
            if (_dateTime.Ticks == _dateTime.Date.Ticks)
            {
                dateValue = new Date(_dateTime);
                return true;
            }
        }
        dateValue = default;
        return false;
    }
    public static int operator -(Date a, Date b)
    {
        return (int)(a._date - b._date).TotalDays;
    }
    public static Date operator +(Date a, int b)
    {
        return a.AddDays(b);
    }
    public static bool operator ==(Date a, Date b)
    {
        return a._date == b._date;
    }
    public static bool operator !=(Date a, Date b)
    {
        return a._date != b._date;
    }
    public static bool operator >(Date a, Date b)
    {
        return a._date > b._date;
    }
    public static bool operator <(Date a, Date b)
    {
        return a._date < b._date;
    }
    public static bool operator >=(Date a, Date b)
    {
        return a._date >= b._date;
    }
    public static bool operator <=(Date a, Date b)
    {
        return a._date <= b._date;
    }
}
